home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 008a / perl40_2.zip / HASH.C < prev    next >
C/C++ Source or Header  |  1991-11-28  |  15KB  |  746 lines

  1. /* $RCSfile: hash.c,v $$Revision: 4.0.1.2 $$Date: 91/11/05 17:24:13 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    hash.c,v $
  9.  * Revision 4.0.1.2  91/11/05  17:24:13  lwall
  10.  * patch11: saberized perl
  11.  *
  12.  * Revision 4.0.1.1  91/06/07  11:10:11  lwall
  13.  * patch4: new copyright notice
  14.  *
  15.  * Revision 4.0  91/03/20  01:22:26  lwall
  16.  * 4.0 baseline.
  17.  *
  18.  */
  19.  
  20.  
  21. #include "EXTERN.h"
  22. #include "perl.h"
  23.  
  24.  
  25. static char coeff[] = {
  26.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  27.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  28.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  29.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  30.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  31.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  32.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  33.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
  34.  
  35.  
  36. static void hfreeentries();
  37.  
  38.  
  39. STR *
  40. hfetch(tb,key,klen,lval)
  41. register HASH *tb;
  42. char *key;
  43. unsigned int klen;
  44. int lval;
  45. {
  46.     register char *s;
  47.     register int i;
  48.     register int hash;
  49.     register HENT *entry;
  50.     register int maxi;
  51.     STR *str;
  52. #ifdef SOME_DBM
  53.     datum dkey,dcontent;
  54. #endif
  55.  
  56.  
  57.     if (!tb)
  58.     return &str_undef;
  59.     if (!tb->tbl_array) {
  60.     if (lval)
  61.         Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
  62.     else
  63.         return &str_undef;
  64.     }
  65.  
  66.  
  67.     /* The hash function we use on symbols has to be equal to the first
  68.      * character when taken modulo 128, so that str_reset() can be implemented
  69.      * efficiently.  We throw in the second character and the last character
  70.      * (times 128) so that long chains of identifiers starting with the
  71.      * same letter don't have to be strEQ'ed within hfetch(), since it
  72.      * compares hash values before trying strEQ().
  73.      */
  74.     if (!tb->tbl_coeffsize)
  75.     hash = *key + 128 * key[1] + 128 * key[klen-1];    /* assuming klen > 0 */
  76.     else {    /* use normal coefficients */
  77.     if (klen < tb->tbl_coeffsize)
  78.         maxi = klen;
  79.     else
  80.         maxi = tb->tbl_coeffsize;
  81.     for (s=key,        i=0,    hash = 0;
  82.                 i < maxi;            /*SUPPRESS 8*/
  83.          s++,        i++,    hash *= 5) {
  84.         hash += *s * coeff[i];
  85.     }
  86.     }
  87.  
  88.  
  89.     entry = tb->tbl_array[hash & tb->tbl_max];
  90.     for (; entry; entry = entry->hent_next) {
  91.     if (entry->hent_hash != hash)        /* strings can't be equal */
  92.         continue;
  93.     if (entry->hent_klen != klen)
  94.         continue;
  95.     if (bcmp(entry->hent_key,key,klen))    /* is this it? */
  96.         continue;
  97.     return entry->hent_val;
  98.     }
  99. #ifdef SOME_DBM
  100.     if (tb->tbl_dbm) {
  101.     dkey.dptr = key;
  102.     dkey.dsize = klen;
  103. #ifdef HAS_GDBM
  104.     dcontent = gdbm_fetch(tb->tbl_dbm,dkey);
  105. #else
  106.     dcontent = dbm_fetch(tb->tbl_dbm,dkey);
  107. #endif
  108.     if (dcontent.dptr) {            /* found one */
  109.         str = Str_new(60,dcontent.dsize);
  110.         str_nset(str,dcontent.dptr,dcontent.dsize);
  111.         hstore(tb,key,klen,str,hash);        /* cache it */
  112.         return str;
  113.     }
  114.     }
  115. #endif
  116.     if (lval) {        /* gonna assign to this, so it better be there */
  117.     str = Str_new(61,0);
  118.     hstore(tb,key,klen,str,hash);
  119.     return str;
  120.     }
  121.     return &str_undef;
  122. }
  123.  
  124.  
  125. bool
  126. hstore(tb,key,klen,val,hash)
  127. register HASH *tb;
  128. char *key;
  129. unsigned int klen;
  130. STR *val;
  131. register int hash;
  132. {
  133.     register char *s;
  134.     register int i;
  135.     register HENT *entry;
  136.     register HENT **oentry;
  137.     register int maxi;
  138.  
  139.  
  140.     if (!tb)
  141.     return FALSE;
  142.  
  143.  
  144.     if (hash)
  145.     /*SUPPRESS 530*/
  146.     ;
  147.     else if (!tb->tbl_coeffsize)
  148.     hash = *key + 128 * key[1] + 128 * key[klen-1];
  149.     else {    /* use normal coefficients */
  150.     if (klen < tb->tbl_coeffsize)
  151.         maxi = klen;
  152.     else
  153.         maxi = tb->tbl_coeffsize;
  154.     for (s=key,        i=0,    hash = 0;
  155.                 i < maxi;            /*SUPPRESS 8*/
  156.          s++,        i++,    hash *= 5) {
  157.         hash += *s * coeff[i];
  158.     }
  159.     }
  160.  
  161.  
  162.     if (!tb->tbl_array)
  163.     Newz(505,tb->tbl_array, tb->tbl_max + 1, HENT*);
  164.  
  165.  
  166.     oentry = &(tb->tbl_array[hash & tb->tbl_max]);
  167.     i = 1;
  168.  
  169.  
  170.     for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
  171.     if (entry->hent_hash != hash)        /* strings can't be equal */
  172.         continue;
  173.     if (entry->hent_klen != klen)
  174.         continue;
  175.     if (bcmp(entry->hent_key,key,klen))    /* is this it? */
  176.         continue;
  177.     Safefree(entry->hent_val);
  178.     entry->hent_val = val;
  179.     return TRUE;
  180.     }
  181.     New(501,entry, 1, HENT);
  182.  
  183.  
  184.     entry->hent_klen = klen;
  185.     entry->hent_key = nsavestr(key,klen);
  186.     entry->hent_val = val;
  187.     entry->hent_hash = hash;
  188.     entry->hent_next = *oentry;
  189.     *oentry = entry;
  190.  
  191.  
  192.     /* hdbmstore not necessary here because it's called from stabset() */
  193.  
  194.  
  195.     if (i) {                /* initial entry? */
  196.     tb->tbl_fill++;
  197. #ifdef SOME_DBM
  198.     if (tb->tbl_dbm && tb->tbl_max >= DBM_CACHE_MAX)
  199.         return FALSE;
  200. #endif
  201.     if (tb->tbl_fill > tb->tbl_dosplit)
  202.         hsplit(tb);
  203.     }
  204. #ifdef SOME_DBM
  205.     else if (tb->tbl_dbm) {        /* is this just a cache for dbm file? */
  206.     void hentdelayfree();
  207.  
  208.  
  209.     entry = tb->tbl_array[hash & tb->tbl_max];
  210.     oentry = &entry->hent_next;
  211.     entry = *oentry;
  212.     while (entry) {    /* trim chain down to 1 entry */
  213.         *oentry = entry->hent_next;
  214.         hentdelayfree(entry);    /* no doubt they'll want this next. */
  215.         entry = *oentry;
  216.     }
  217.     }
  218. #endif
  219.  
  220.  
  221.     return FALSE;
  222. }
  223.  
  224.  
  225. STR *
  226. hdelete(tb,key,klen)
  227. register HASH *tb;
  228. char *key;
  229. unsigned int klen;
  230. {
  231.     register char *s;
  232.     register int i;
  233.     register int hash;
  234.     register HENT *entry;
  235.     register HENT **oentry;
  236.     STR *str;
  237.     int maxi;
  238. #ifdef SOME_DBM
  239.     datum dkey;
  240. #endif
  241.  
  242.  
  243.     if (!tb || !tb->tbl_array)
  244.     return Nullstr;
  245.     if (!tb->tbl_coeffsize)
  246.     hash = *key + 128 * key[1] + 128 * key[klen-1];
  247.     else {    /* use normal coefficients */
  248.     if (klen < tb->tbl_coeffsize)
  249.         maxi = klen;
  250.     else
  251.         maxi = tb->tbl_coeffsize;
  252.     for (s=key,        i=0,    hash = 0;
  253.                 i < maxi;            /*SUPPRESS 8*/
  254.          s++,        i++,    hash *= 5) {
  255.         hash += *s * coeff[i];
  256.     }
  257.     }
  258.  
  259.  
  260.     oentry = &(tb->tbl_array[hash & tb->tbl_max]);
  261.     entry = *oentry;
  262.     i = 1;
  263.     for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
  264.     if (entry->hent_hash != hash)        /* strings can't be equal */
  265.         continue;
  266.     if (entry->hent_klen != klen)
  267.         continue;
  268.     if (bcmp(entry->hent_key,key,klen))    /* is this it? */
  269.         continue;
  270.     *oentry = entry->hent_next;
  271.     str = str_mortal(entry->hent_val);
  272.     hentfree(entry);
  273.     if (i)
  274.         tb->tbl_fill--;
  275. #ifdef SOME_DBM
  276.       do_dbm_delete:
  277.     if (tb->tbl_dbm) {
  278.         dkey.dptr = key;
  279.         dkey.dsize = klen;
  280. #ifdef HAS_GDBM
  281.         gdbm_delete(tb->tbl_dbm,dkey);
  282. #else
  283.         dbm_delete(tb->tbl_dbm,dkey);
  284. #endif
  285.     }
  286. #endif
  287.     return str;
  288.     }
  289. #ifdef SOME_DBM
  290.     str = Nullstr;
  291.     goto do_dbm_delete;
  292. #else
  293.     return Nullstr;
  294. #endif
  295. }
  296.  
  297.  
  298. hsplit(tb)
  299. HASH *tb;
  300. {
  301.     int oldsize = tb->tbl_max + 1;
  302.     register int newsize = oldsize * 2;
  303.     register int i;
  304.     register HENT **a;
  305.     register HENT **b;
  306.     register HENT *entry;
  307.     register HENT **oentry;
  308.  
  309.  
  310.     a = tb->tbl_array;
  311.     Renew(a, newsize, HENT*);
  312.     Zero(&a[oldsize], oldsize, HENT*);        /* zero 2nd half*/
  313.     tb->tbl_max = --newsize;
  314.     tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
  315.     tb->tbl_array = a;
  316.  
  317.  
  318.     for (i=0; i<oldsize; i++,a++) {
  319.     if (!*a)                /* non-existent */
  320.         continue;
  321.     b = a+oldsize;
  322.     for (oentry = a, entry = *a; entry; entry = *oentry) {
  323.         if ((entry->hent_hash & newsize) != i) {
  324.         *oentry = entry->hent_next;
  325.         entry->hent_next = *b;
  326.         if (!*b)
  327.             tb->tbl_fill++;
  328.         *b = entry;
  329.         continue;
  330.         }
  331.         else
  332.         oentry = &entry->hent_next;
  333.     }
  334.     if (!*a)                /* everything moved */
  335.         tb->tbl_fill--;
  336.     }
  337. }
  338.  
  339.  
  340. HASH *
  341. hnew(lookat)
  342. unsigned int lookat;
  343. {
  344.     register HASH *tb;
  345.  
  346.  
  347.     Newz(502,tb, 1, HASH);
  348.     if (lookat) {
  349.     tb->tbl_coeffsize = lookat;
  350.     tb->tbl_max = 7;        /* it's a normal associative array */
  351.     tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
  352.     }
  353.     else {
  354.     tb->tbl_max = 127;        /* it's a symbol table */
  355.     tb->tbl_dosplit = 128;        /* so never split */
  356.     }
  357.     tb->tbl_fill = 0;
  358. #ifdef SOME_DBM
  359.     tb->tbl_dbm = 0;
  360. #endif
  361.     (void)hiterinit(tb);    /* so each() will start off right */
  362.     return tb;
  363. }
  364.  
  365.  
  366. void
  367. hentfree(hent)
  368. register HENT *hent;
  369. {
  370.     if (!hent)
  371.     return;
  372.     str_free(hent->hent_val);
  373.     Safefree(hent->hent_key);
  374.     Safefree(hent);
  375. }
  376.  
  377.  
  378. void
  379. hentdelayfree(hent)
  380. register HENT *hent;
  381. {
  382.     if (!hent)
  383.     return;
  384.     str_2mortal(hent->hent_val);    /* free between statements */
  385.     Safefree(hent->hent_key);
  386.     Safefree(hent);
  387. }
  388.  
  389.  
  390. void
  391. hclear(tb,dodbm)
  392. register HASH *tb;
  393. int dodbm;
  394. {
  395.     if (!tb)
  396.     return;
  397.     hfreeentries(tb,dodbm);
  398.     tb->tbl_fill = 0;
  399. #ifndef lint
  400.     if (tb->tbl_array)
  401.     (void)bzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
  402. #endif
  403. }
  404.  
  405.  
  406. static void
  407. hfreeentries(tb,dodbm)
  408. register HASH *tb;
  409. int dodbm;
  410. {
  411.     register HENT *hent;
  412.     register HENT *ohent = Null(HENT*);
  413. #ifdef SOME_DBM
  414.     datum dkey;
  415.     datum nextdkey;
  416. #ifdef HAS_GDBM
  417.     GDBM_FILE old_dbm;
  418. #else
  419. #ifdef HAS_NDBM
  420.     DBM *old_dbm;
  421. #else
  422.     int old_dbm;
  423. #endif
  424. #endif
  425. #endif
  426.  
  427.  
  428.     if (!tb || !tb->tbl_array)
  429.     return;
  430. #ifdef SOME_DBM
  431.     if ((old_dbm = tb->tbl_dbm) && dodbm) {
  432. #ifdef HAS_GDBM
  433.     while (dkey = gdbm_firstkey(tb->tbl_dbm), dkey.dptr) {
  434. #else
  435.     while (dkey = dbm_firstkey(tb->tbl_dbm), dkey.dptr) {
  436. #endif
  437.         do {
  438. #ifdef HAS_GDBM
  439.         nextdkey = gdbm_nextkey(tb->tbl_dbm, dkey);
  440. #else
  441. #ifdef HAS_NDBM
  442. #ifdef _CX_UX
  443.         nextdkey = dbm_nextkey(tb->tbl_dbm, dkey);
  444. #else
  445.         nextdkey = dbm_nextkey(tb->tbl_dbm);
  446. #endif
  447. #else
  448.         nextdkey = nextkey(dkey);
  449. #endif
  450. #endif
  451. #ifdef HAS_GDBM
  452.         gdbm_delete(tb->tbl_dbm,dkey);
  453. #else
  454.         dbm_delete(tb->tbl_dbm,dkey);
  455. #endif
  456.         dkey = nextdkey;
  457.         } while (dkey.dptr);    /* one way or another, this works */
  458.     }
  459.     }
  460.     tb->tbl_dbm = 0;            /* now clear just cache */
  461. #endif
  462.     (void)hiterinit(tb);
  463.     /*SUPPRESS 560*/
  464.     while (hent = hiternext(tb)) {    /* concise but not very efficient */
  465.     hentfree(ohent);
  466.     ohent = hent;
  467.     }
  468.     hentfree(ohent);
  469. #ifdef SOME_DBM
  470.     tb->tbl_dbm = old_dbm;
  471. #endif
  472. }
  473.  
  474.  
  475. void
  476. hfree(tb,dodbm)
  477. register HASH *tb;
  478. int dodbm;
  479. {
  480.     if (!tb)
  481.     return;
  482.     hfreeentries(tb,dodbm);
  483.     Safefree(tb->tbl_array);
  484.     Safefree(tb);
  485. }
  486.  
  487.  
  488. int
  489. hiterinit(tb)
  490. register HASH *tb;
  491. {
  492.     tb->tbl_riter = -1;
  493.     tb->tbl_eiter = Null(HENT*);
  494.     return tb->tbl_fill;
  495. }
  496.  
  497.  
  498. HENT *
  499. hiternext(tb)
  500. register HASH *tb;
  501. {
  502.     register HENT *entry;
  503. #ifdef SOME_DBM
  504.     datum key;
  505. #endif
  506.  
  507.  
  508.     entry = tb->tbl_eiter;
  509. #ifdef SOME_DBM
  510.     if (tb->tbl_dbm) {
  511.     if (entry) {
  512. #ifdef HAS_GDBM
  513.         key.dptr = entry->hent_key;
  514.         key.dsize = entry->hent_klen;
  515.         key = gdbm_nextkey(tb->tbl_dbm, key);
  516. #else
  517. #ifdef HAS_NDBM
  518. #ifdef _CX_UX
  519.         key.dptr = entry->hent_key;
  520.         key.dsize = entry->hent_klen;
  521.         key = dbm_nextkey(tb->tbl_dbm, key);
  522. #else
  523.         key = dbm_nextkey(tb->tbl_dbm);
  524. #endif /* _CX_UX */
  525. #else
  526.         key.dptr = entry->hent_key;
  527.         key.dsize = entry->hent_klen;
  528.         key = nextkey(key);
  529. #endif
  530. #endif
  531.     }
  532.     else {
  533.         Newz(504,entry, 1, HENT);
  534.         tb->tbl_eiter = entry;
  535. #ifdef HAS_GDBM
  536.         key = gdbm_firstkey(tb->tbl_dbm);
  537. #else
  538.         key = dbm_firstkey(tb->tbl_dbm);
  539. #endif
  540.     }
  541.     entry->hent_key = key.dptr;
  542.     entry->hent_klen = key.dsize;
  543.     if (!key.dptr) {
  544.         if (entry->hent_val)
  545.         str_free(entry->hent_val);
  546.         Safefree(entry);
  547.         tb->tbl_eiter = Null(HENT*);
  548.         return Null(HENT*);
  549.     }
  550.     return entry;
  551.     }
  552. #endif
  553.     if (!tb->tbl_array)
  554.     Newz(506,tb->tbl_array, tb->tbl_max + 1, HENT*);
  555.     do {
  556.     if (entry)
  557.         entry = entry->hent_next;
  558.     if (!entry) {
  559.         tb->tbl_riter++;
  560.         if (tb->tbl_riter > tb->tbl_max) {
  561.         tb->tbl_riter = -1;
  562.         break;
  563.         }
  564.         entry = tb->tbl_array[tb->tbl_riter];
  565.     }
  566.     } while (!entry);
  567.  
  568.  
  569.     tb->tbl_eiter = entry;
  570.     return entry;
  571. }
  572.  
  573.  
  574. char *
  575. hiterkey(entry,retlen)
  576. register HENT *entry;
  577. int *retlen;
  578. {
  579.     *retlen = entry->hent_klen;
  580.     return entry->hent_key;
  581. }
  582.  
  583.  
  584. STR *
  585. hiterval(tb,entry)
  586. register HASH *tb;
  587. register HENT *entry;
  588. {
  589. #ifdef SOME_DBM
  590.     datum key, content;
  591.  
  592.  
  593.     if (tb->tbl_dbm) {
  594.     key.dptr = entry->hent_key;
  595.     key.dsize = entry->hent_klen;
  596. #ifdef HAS_GDBM
  597.     content = gdbm_fetch(tb->tbl_dbm,key);
  598. #else
  599.     content = dbm_fetch(tb->tbl_dbm,key);
  600. #endif
  601.     if (!entry->hent_val)
  602.         entry->hent_val = Str_new(62,0);
  603.     str_nset(entry->hent_val,content.dptr,content.dsize);
  604.     }
  605. #endif
  606.     return entry->hent_val;
  607. }
  608.  
  609.  
  610. #ifdef SOME_DBM
  611.  
  612.  
  613. #ifndef O_CREAT
  614. #  ifdef I_FCNTL
  615. #    include <fcntl.h>
  616. #  endif
  617. #  ifdef I_SYS_FILE
  618. #    include <sys/file.h>
  619. #  endif
  620. #endif
  621.  
  622.  
  623. #ifndef O_RDONLY
  624. #define O_RDONLY 0
  625. #endif
  626. #ifndef O_RDWR
  627. #define O_RDWR 2
  628. #endif
  629. #ifndef O_CREAT
  630. #define O_CREAT 01000
  631. #endif
  632.  
  633.  
  634. #ifdef HAS_ODBM
  635. static int dbmrefcnt = 0;
  636. #endif
  637.  
  638.  
  639. bool
  640. hdbmopen(tb,fname,mode)
  641. register HASH *tb;
  642. char *fname;
  643. int mode;
  644. {
  645.     if (!tb)
  646.     return FALSE;
  647. #ifdef HAS_ODBM
  648.     if (tb->tbl_dbm)    /* never really closed it */
  649.     return TRUE;
  650. #endif
  651.     if (tb->tbl_dbm) {
  652.     hdbmclose(tb);
  653.     tb->tbl_dbm = 0;
  654.     }
  655.     hclear(tb, FALSE);    /* clear cache */
  656. #ifdef HAS_GDBM
  657.     if (mode >= 0)
  658.     tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRCREAT,mode, (void *) NULL);
  659.     if (!tb->tbl_dbm)
  660.     tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRITER, mode, (void *) NULL);
  661.     if (!tb->tbl_dbm)
  662.     tb->tbl_dbm = gdbm_open(fname, 0, GDBM_READER, mode, (void *) NULL);
  663. #else
  664. #ifdef HAS_NDBM
  665.     if (mode >= 0)
  666.     tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
  667.     if (!tb->tbl_dbm)
  668.     tb->tbl_dbm = dbm_open(fname, O_RDWR, mode);
  669.     if (!tb->tbl_dbm)
  670.     tb->tbl_dbm = dbm_open(fname, O_RDONLY, mode);
  671. #else
  672.     if (dbmrefcnt++)
  673.     fatal("Old dbm can only open one database");
  674.     sprintf(buf,"%s.dir",fname);
  675.     if (stat(buf, &statbuf) < 0) {
  676.     if (mode < 0 || close(creat(buf,mode)) < 0)
  677.         return FALSE;
  678.     sprintf(buf,"%s.pag",fname);
  679.     if (close(creat(buf,mode)) < 0)
  680.         return FALSE;
  681.     }
  682.     tb->tbl_dbm = dbminit(fname) >= 0;
  683. #endif
  684. #endif
  685.     if (!tb->tbl_array && tb->tbl_dbm != 0)
  686.     Newz(507,tb->tbl_array, tb->tbl_max + 1, HENT*);
  687.     return tb->tbl_dbm != 0;
  688. }
  689.  
  690.  
  691. void
  692. hdbmclose(tb)
  693. register HASH *tb;
  694. {
  695.     if (tb && tb->tbl_dbm) {
  696. #ifdef HAS_GDBM
  697.     gdbm_close(tb->tbl_dbm);
  698.     tb->tbl_dbm = 0;
  699. #else
  700. #ifdef HAS_NDBM
  701.     dbm_close(tb->tbl_dbm);
  702.     tb->tbl_dbm = 0;
  703. #else
  704.     /* dbmrefcnt--;  */    /* doesn't work, rats */
  705. #endif
  706. #endif
  707.     }
  708.     else if (dowarn)
  709.     warn("Close on unopened dbm file");
  710. }
  711.  
  712.  
  713. bool
  714. hdbmstore(tb,key,klen,str)
  715. register HASH *tb;
  716. char *key;
  717. unsigned int klen;
  718. register STR *str;
  719. {
  720.     datum dkey, dcontent;
  721.     int error;
  722.  
  723.  
  724.     if (!tb || !tb->tbl_dbm)
  725.     return FALSE;
  726.     dkey.dptr = key;
  727.     dkey.dsize = klen;
  728.     dcontent.dptr = str_get(str);
  729.     dcontent.dsize = str->str_cur;
  730. #ifdef HAS_GDBM
  731.     error = gdbm_store(tb->tbl_dbm, dkey, dcontent, GDBM_REPLACE);
  732. #else
  733.     error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
  734. #endif
  735.     if (error) {
  736.     if (errno == EPERM)
  737.         fatal("No write permission to dbm file");
  738.     warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
  739. #ifdef HAS_NDBM
  740.         dbm_clearerr(tb->tbl_dbm);
  741. #endif
  742.     }
  743.     return !error;
  744. }
  745. #endif /* SOME_DBM */
  746.